from expression import expression
from expression import environment 
from jsobject import closure
import sys
sys.path.append(sys.path[0] + "/../LLVM")
from llvmhelper import llvmHelper
from llvm import *
from commonRoutines import commonRoutines

class functionBinding(expression):
	def __init__(self, functions, body):
		if(len(functions) == 0):
			print "ERROR:Figure out how in gods name we have a functionBinding with 0 functions!!!!"
		self.functions = functions # function defs
		self.body = body
		
	def evaluate(self, env):
		#print "FunBind: ",
		functions = self.functions
		funcClosures = []
		#functions = []
		#for scopedF in scopedfunctions:
		#	functions.append(scopedF.getNext())	
		
		#First, make all the closures
		for f in functions:
			newclosure = closure(f.getParams(),f.getBody(),env, f.getFunNum())
			funcClosures.append(newclosure)
			
		#ex: functions: [a(),b()], closures: [a(), b()]
		newEnv = env
		i = 0
		
		for f in functions:
			# add each closure the environment
			#print f.getName(), ", ",
			newEnv = environment(f.getName(),funcClosures[i],newEnv)
			i += 1
		
		#print "Funbinding env", str(newEnv)
		# newEnv <- a(), b()
		# add all closures to all other closures
		# I really hope this works
		for c in funcClosures:
			for j in range(0, len(functions)):
				thisEnv = c.getEnv()
				thisEnv = environment(functions[j].getName(), funcClosures[j], thisEnv)
				c.setEnv(thisEnv)
		#print "Env in functBind: ", str(newEnv)		
		self.body.evaluate(newEnv)
	def __str__(self):
		value =  " FunBinding([\n"
		for f in self.functions:
			value += str(f) + ","
		value += "],"
		value += str(self.body) + ")" 
		return value

	def traverse(self, helper):
		for f in self.functions:
			f.traverse(helper)
		#now traverse the bodys of the function
		for f in self.functions:
			f.body.traverse(helper)
		#TODO Add the functions to the helper
		#print "Traversing function on " + str(self.body)
		self.body.traverse(helper)

	def toLLVM(self, helper):
		helper.descend("functionBinding")
		for f in self.functions:
			f.toLLVM(helper)
		
		self.body.toLLVM(helper)
		
		helper.setLabel(helper.getLastLabel())
		helper.ascend(helper.getReturns()[-1])

